package com.strp.mptcp.common;

import io.netty.buffer.ByteBuf;
import lombok.Getter;

/**
* @author 曹行阳
* @date 2025/6/12 11:28
* @version 0.1
*/
public record DataChunk(
        Header header,
        ByteBuf payload
) {
    // 头部固定长度，便于解析
    public static final int HEADER_LENGTH = 1 + 4 + 8 + 8; // type + pathId + seq + ack

    @Getter
    public enum ChunkType {
        DATA((byte) 0x01),
        ACK((byte) 0x02),
        HEARTBEAT((byte) 0x03),
        HEARTBEAT_ACK((byte) 0x04),
        FIN((byte) 0x05), // 文件传输结束标记
        FIN_ACK((byte) 0x06);

        private final byte value;
        ChunkType(byte value) { this.value = value; }

        public static ChunkType fromByte(byte b) {
            for (ChunkType type : values()) {
                if (type.value == b) return type;
            }
            throw new IllegalArgumentException("Unknown chunk type: " + b);
        }
    }

    // MPTCP 头部信息
    public record Header(
            ChunkType type,
            int pathId,       // 子流 ID
            long sequence,    // 全局数据序列号 (Data Sequence)
            long ack         // 确认号
    ) {
    }

    // 编码到 ByteBuf
    public void encode(ByteBuf out) {
        out.writeByte(header.type.getValue());
        out.writeInt(header.pathId);
        out.writeLong(header.sequence);
        out.writeLong(header.ack);
        if (payload != null) {
            out.writeBytes(payload);
        }
    }

    // 从 ByteBuf 解码
    public static DataChunk decode(ByteBuf in) {
        if (in.readableBytes() < HEADER_LENGTH) {
            return null; // 数据不足，等待更多数据
        }
        byte typeByte = in.readByte();
        ChunkType type = ChunkType.fromByte(typeByte);
        int pathId = in.readInt();
        long sequence = in.readLong();
        long ack = in.readLong();
        Header header = new Header(type, pathId, sequence, ack);

        // 复制 payload，避免 readerIndex 影响外部逻辑
        ByteBuf payload = in.copy(in.readerIndex(), in.readableBytes());
        in.skipBytes(in.readableBytes()); // 消费掉所有剩余字节

        return new DataChunk(header, payload);
    }
}
